import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Random;

public class CardgameMain {
	public static int compareHand(ArrayList <Card> playerHand, ArrayList <Card>compHand){
		int pScore=handValue(playerHand);
		int cScore=handValue(compHand);
		int result=0;
		if ((cScore==pScore) || ((pScore>21) && (cScore>21))){
			result=3;
		}
		else if ((pScore>cScore && pScore<=21) || (cScore>21)){
			result=1;
		}
		else if ((pScore<cScore && cScore<=21) || (pScore>21)){
			result=2;
		}
		
		return result;
	}
	public static ArrayList <Card> reshuffle(ArrayList <Card> discardPile, ArrayList <Card> cardDeck){
		int disSize=discardPile.size();
		for (int counter=0; counter<disSize; counter++){
			cardDeck.add(discardPile.get(0));
			discardPile.remove(0);
		}
		shuffle(cardDeck);
		return cardDeck;
	}
	public static ArrayList <Card> createHand(ArrayList <Card> hand, ArrayList <Card> cardDeck){
		for (int counter=0; counter<2; counter++){
			hand.add(cardDeck.get(0));
			cardDeck.remove(0);
		}
		return hand;
	}
	public static void revealHand(ArrayList <Card> playerHand, ArrayList <Card>compHand){
		Card tempCard= null;
		System.out.println("It is time to reveal the hands...");
		breakScreen();
		System.out.println("Your hand:");
		for(int counter=0; counter<playerHand.size(); counter++){
			tempCard=playerHand.get(counter);
			if (counter==0)
				System.out.println("Face up card:");
			else
				System.out.println("Other card(s):");
			System.out.println((counter+1) + ")\t" + tempCard.getCardName() + " of " + tempCard.getCardSuit());	
		}
		System.out.println("Your hand's value:\t"+ handValue(playerHand));
		if (handValue(playerHand)>21)
			System.out.println("You went over!");
		breakScreen();
		System.out.println("Dealer's hand:");
		for(int counter=0; counter<compHand.size(); counter++){
			tempCard=compHand.get(counter);
			if (counter==0)
				System.out.println("Face up card:");
			else
				System.out.println("Other card(s):");
			System.out.println((counter+1) + ")\t" + tempCard.getCardName() + " of " + tempCard.getCardSuit());	
		}
		System.out.println("Dealer's hand's value:\t"+ handValue(compHand));
		if (handValue(compHand)>21)
			System.out.println("Dealer went over!");
	}	
	public static int gameMenu(int round){
		Scanner in;
		boolean viewMenu=true;
		int playerSelect=0;
		while (viewMenu){
			System.out.println("What would you like do to?");
			System.out.println("1:\tHit\n2:\tStand");
			if (round==1){
				System.out.println("3:\tDouble Down");
			}
			in= new Scanner(System.in);
			try{
				playerSelect=in.nextInt();
			}
			catch (NumberFormatException | InputMismatchException e){
				playerSelect=0;
				System.out.println("That is not a number!");
			}
			if ((playerSelect==1 || playerSelect==2) || (playerSelect==3 && round==1)){
				viewMenu=false;
			}
			else{
				breakScreen();
			}
		}
		return playerSelect;
}
	public static ArrayList <Card> discard(ArrayList <Card> discardPile, ArrayList <Card> playerHand, ArrayList <Card>compHand){
		int sizephand=playerHand.size();
		int sizeohand=compHand.size();
		for (int counter=0; counter<sizephand; counter++){
			discardPile.add(playerHand.get(0));
			playerHand.remove(0);
		}
		for (int counter=0; counter<sizeohand; counter++){
			discardPile.add(compHand.get(0));
			compHand.remove(0);
		}
		return discardPile;
	}
	public static ArrayList <Card> drawCard(ArrayList <Card> hand, ArrayList <Card> cardDeck){
		hand.add(cardDeck.get(0));
		cardDeck.remove(0);
		return hand;
	}
	public static void viewCard(ArrayList <Card> playerHand, ArrayList <Card>compHand){
		Card tempCard= null;
		System.out.println("Your Hand:");
		for(int counter=0; counter<playerHand.size(); counter++){
			tempCard=playerHand.get(counter);
			if (counter==0)
				System.out.println("Face up card:");
			else
				System.out.println("Other card(s):");
			System.out.println((counter+1) + ")\t" + tempCard.getCardName() + " of " + tempCard.getCardSuit());	
		}
		System.out.println("Your hand's value:\t"+ handValue(playerHand));
		if (handValue(playerHand)>21)
			System.out.println("You went over!");
		breakScreen();
		tempCard=compHand.get(0);
		System.out.println("Dealer's Hand:");
		System.out.println("Face up card:");
		System.out.println(tempCard.getCardName() + " of " + tempCard.getCardSuit());
		System.out.println("He has " + (compHand.size()-1) + " face down card(s)");
	}
	public static void breakScreen(){
		System.out.println("\n. . . . . .\n");
	}
	public static ArrayList <Card> shuffle(ArrayList <Card> deck){
		Random randGen= new Random();	
		int temp=0;
		for (int shuffleCount=0; shuffleCount<deck.size(); shuffleCount++){
			temp=randGen.nextInt(deck.size()-shuffleCount) + shuffleCount;
			Collections.swap(deck, temp, shuffleCount);
		}
		return deck;
	}
	public static int compHit(ArrayList <Card> oHand, ArrayList <Card> pHand){
		Card upCard=pHand.get(0);
		if (((handValue(oHand)>13) && (upCard.getCardValue()>6))||(handValue(oHand)>16)){
			return 0;
		}
		else
			return 1;
	}
	public static void saveData(int playerCash){
		FileOutputStream saveFile = null;
		try {
			saveFile = new FileOutputStream("C:/Users/Student/My Documents/storeCash.txt");
		} catch (FileNotFoundException e) {
			System.out.println("There was an error (301)");
			e.printStackTrace();
		}
		DataOutputStream saveStore= new DataOutputStream(saveFile);
		try {
			saveStore.writeInt(playerCash);
		} catch (IOException e) {
			System.out.println("There was an error (302)");
			e.printStackTrace();
		}
	}
	public static int readData(){
		FileInputStream saveReader= null;
		BufferedInputStream saveBuff= null;
		DataInputStream dataReader= null;
		int storedCash= 0;
		try {
			saveReader= new FileInputStream("C:/Users/Student/My Documents/storeCash.txt");
			saveBuff= new BufferedInputStream(saveReader);
			dataReader= new DataInputStream(saveBuff);
		} catch (FileNotFoundException e) {
			System.out.println("There was an error (201)");
			e.printStackTrace();
		}
		try {
			while (dataReader.available()!=0){
				storedCash=dataReader.readInt();
			}
		} catch (IOException e) {
			System.out.println("There was an error (202)");
			e.printStackTrace();
		}
		return storedCash;
	}
	public static int placeBet(int playerCash){
		boolean viewBet=true;
		int bet=0;
		while (viewBet==true){
			bet=-1000;
			System.out.println("How much would you like to bet?");
			Scanner in= new Scanner(System.in);
			try{
				bet=in.nextInt();
			}
			catch (NumberFormatException | InputMismatchException e){
				System.out.println("That is not a number!");
			}
			if (bet<=playerCash && bet>=0){
				viewBet=false;
			}
			else
				System.out.println("You can't bet more than what you have");
		}
		System.out.println("You place your bet of " + bet + "$");
		return bet;
	}
	public static int handValue(ArrayList <Card> hand){
		int total=0;
		Card tempCard= null;
		for (int normCount=0; normCount<hand.size(); normCount++){
			tempCard=hand.get(normCount);
			if (tempCard.getCardAce()==false){
				total=total+tempCard.getCardValue();
			}
		}
		for (int aceCounter=0; aceCounter<hand.size(); aceCounter++){
			tempCard=hand.get(aceCounter);
			if (tempCard.getCardAce()==true){
				if (total+11>21){
				total=total+1;
				}
				else if (total+11<=21){
				total=total+11;
				}
			}
		}
		return total;
	}
	public static int modCash(int bet, int cash){
		cash=cash-bet;
		return cash;
	}
	public static int saveMenu(){
		Scanner in;
		boolean saveMenu=true;
		int playerSelect = 0;
		while (saveMenu){
			System.out.println("Would you like to save your game?\n1:\tSave & Quit\n2:\tQuit without Saving");
			in= new Scanner(System.in);
			try{
				playerSelect=in.nextInt();
			}
			catch (NumberFormatException | InputMismatchException e){
				playerSelect=0;
				System.out.println("That is not a number!");
			}
			if (playerSelect==1 || playerSelect==2){
				saveMenu=false;
			}
			else{
				breakScreen();
			}
		}
		return playerSelect;
	}
	public static int mainMenu(){
		Scanner in;
		boolean viewMenu=true;
		int playerSelect = 0;
		while (viewMenu){
			System.out.println("Welcome to BlackJack\n1:\tNew Game\n2:\tContinue");
			in= new Scanner(System.in);
			try{
				playerSelect=in.nextInt();
			}
			catch (NumberFormatException | InputMismatchException e){
				playerSelect=0;
				System.out.println("That is not a number!");
			}
			if (playerSelect==1 || playerSelect==2){
				viewMenu=false;
			}
			else{
				breakScreen();
			}
		}
		return playerSelect;
	}
	public static int continueMenu(){
		Scanner in;
		boolean viewMenu=true;
		int playerSelect = 0;
		while (viewMenu){
			System.out.println("Would you like to play again?\n1:\tYes\n2:\tNo");
			in= new Scanner(System.in);
			try{
				playerSelect=in.nextInt();
			}
			catch (NumberFormatException | InputMismatchException e){
				playerSelect=0;
				System.out.println("That is not a number!");
			}
			if (playerSelect==1 || playerSelect==2){
				viewMenu=false;
			}
			else{
				breakScreen();
			}
		}
		return playerSelect;
	}
	public static void main(String args[]){
		ArrayList <Card> cardDeck= new ArrayList <Card>();
		ArrayList <Card> playerHand= new ArrayList <Card>();
		ArrayList <Card> compHand= new ArrayList <Card>();
		ArrayList <Card> discardPile= new ArrayList <Card>();
		String cardSuit = null;
		int cardValue = 0;
		String[] suitList= {"Clubs","Diamonds", "Hearts","Spades"};
		for (int suitCount=0; suitCount<4; suitCount++){
			for (int valueCount=1; valueCount<=13; valueCount++){
				cardSuit=suitList[suitCount];
				cardValue=valueCount;
				Card tempCard=new Card(cardValue, cardSuit);
				cardDeck.add(tempCard);
			}
		}
		cardDeck=shuffle(cardDeck);
		int playerCash = 0;
		int select=mainMenu();
		if (select==1){
			playerCash=10000;
		}
		else if (select==2){
			playerCash=readData();
		} 
		else{
			playerCash=20000;
		}
		boolean gamePlay=true;
		while (gamePlay==true && playerCash>0){
			int bet=0;
			System.out.println("You have " + playerCash + "$");
			bet=placeBet(playerCash);
			breakScreen();
			playerCash=modCash(bet,playerCash);
			playerHand=createHand(playerHand, cardDeck);
			compHand=createHand(compHand, cardDeck);
			boolean gameRound=true;
			boolean compCont=true;
			int round=1;
			if (handValue(compHand)==21){
				compCont=false;
			}
			if (handValue(playerHand)==21){
				gameRound=false;
				Card tempCard=playerHand.get(0);
				Card tempCard2=playerHand.get(1);
				viewCard(playerHand, compHand);
				if ((tempCard.getCardName().equalsIgnoreCase("Jack")) || tempCard2.getCardName().equalsIgnoreCase("Jack"));
					System.out.println("You have a blackjack!");
			}
			while(gameRound){
				viewCard(playerHand, compHand);
				breakScreen();
				select=gameMenu(round);
				if (select==1){
					System.out.println("You hit.");
					playerHand=drawCard(playerHand, cardDeck);
				}
				else if (select==2){
					System.out.println("You stand.");
					gameRound=false;
				}
				else if (select==3 && round==1){
					System.out.println("You double down.");
					if (playerCash-bet<0){
						System.out.println("You cannot double down as you don't have the money.\nYou hit.");
					}
					else{
						bet=bet*2;
						modCash(bet, playerCash);
						System.out.println("Your bet is now " + bet + "$");
						gameRound=false;
					}
					playerHand=drawCard(playerHand, cardDeck);
				}
				else{
					System.out.println("Error 501");
				}
				if (handValue(playerHand)>=21){
					gameRound=false;
				}
				if (handValue(compHand)<21){
					int compAI=compHit(compHand, playerHand);
					if (compAI==0){
						compCont=false;
					}
					if (compAI==1){
						compHand=drawCard(compHand, cardDeck);
					}
				}
				breakScreen();
				round++;
			}
			while (compCont==true){
				if (handValue(compHand)<21){
					int compAI=compHit(compHand, playerHand);
					if (compAI==0){
						compCont=false;
					}
					if (compAI==1){
						compHand=drawCard(compHand, cardDeck);
					}
				}
				else{
					compCont=false;
				}
			}
			revealHand(playerHand, compHand);
			breakScreen();
			int result=compareHand(playerHand, compHand);
			if (result==1){
				System.out.println("Your hand beats his!\nYou win!");
				System.out.println("You earned " + bet + "$");
				playerCash=playerCash+(2*bet);
			}
			else if (result==2){
				System.out.println("His hand beats yours!\nYou lose.");
				System.out.println("You lost " + bet + "$");
				if (playerCash<0){
					System.out.println("You are out of money!\nYou are out of the game");
				}
			}
			else if (result==3){
				System.out.println("Both hands are equal.\nIt is a tie");
				System.out.println("Your bet, " + bet + "$, has been returned");
				playerCash=playerCash+bet;
			}
			breakScreen();
			discardPile=discard(discardPile, playerHand, compHand);
			if (cardDeck.size()<12){
				System.out.println("The deck has been shuffled");
				cardDeck=reshuffle(discardPile, cardDeck);
			}
			System.out.println("You have " + playerCash + "$");
			breakScreen();
			int contSel=continueMenu();
			if (playerCash<0){
				contSel=2;
				System.out.println("You cannot continue!");
			}
			if (contSel==1){
			System.out.println("New Hand:");
			breakScreen();
			}
			if (contSel==2){
				gamePlay=false;
			}
		}
		if (playerCash>0){
			select=saveMenu();
			if (select==1 && playerCash<0){
				select=2;
				System.out.print("You cannot save!");
			}
			if (select==1){
				saveData(playerCash);
			}
		}
		System.out.println("Goodbye. See you next time");
	}
}

